#include <AudioToolbox/AudioToolbox.h>
#include <pthread.h>
#include <string.h>
#include "logger.h"
#include "pcm-player.h"

static AudioStreamBasicDescription audioFormat;
static int g_channels;
static int g_samplerate;
static int g_bits_per_sample;
#define NUM_BUFFERS 8
typedef struct {
    AudioQueueRef audioQueue;
    AudioQueueBufferRef buffers[NUM_BUFFERS];
    UInt32 bufferByteSize;
    int bufferIndex;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    int isInitialized; // 添加初始化状态标志
} AudioPlayerState;
static AudioPlayerState playerState;

// 回调函数
static void AudioQueueCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
    AudioPlayerState *playerState = (AudioPlayerState *)inUserData;
    // 发送信号通知工作线程
    pthread_mutex_lock(&playerState->mutex);
    inBuffer->mUserData = (void *)0;
    pthread_cond_signal(&playerState->cond);
    pthread_mutex_unlock(&playerState->mutex);

}

static int check_audiotoolbox_support() {
    // 检查是否能调用 AudioToolbox 函数
    return 1;
}

static int pcmPlayer_init(int channels, int samplerate, int bits_per_sample) {
    // 确保在初始化前清空状态
    memset(&playerState, 0, sizeof(AudioPlayerState));
    
    g_channels = channels;
    g_samplerate = samplerate;
    g_bits_per_sample = bits_per_sample;

    audioFormat.mSampleRate = samplerate;
    audioFormat.mFormatID = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    audioFormat.mFramesPerPacket = 1;
    audioFormat.mChannelsPerFrame = channels;
    audioFormat.mBitsPerChannel = bits_per_sample;
    audioFormat.mBytesPerPacket = (bits_per_sample / 8) * channels;
    audioFormat.mBytesPerFrame = (bits_per_sample / 8) * channels;

    // 创建音频输出队列
    OSStatus status = AudioQueueNewOutput(&audioFormat, AudioQueueCallback, &playerState, NULL, kCFRunLoopCommonModes, 0, &playerState.audioQueue);
    if (status != noErr) {
        elog("AudioQueueNewOutput failed: %d\n", status);
        return -1;
    }

    // 分配音频缓冲区
    playerState.bufferByteSize = 8192; // 缓冲区大小
    for (int i = 0; i < NUM_BUFFERS; i++) {
        status = AudioQueueAllocateBuffer(playerState.audioQueue, playerState.bufferByteSize, &playerState.buffers[i]);
        if (status != noErr) {
            elog("AudioQueueAllocateBuffer failed: %d\n", (int)status);
            // 释放已分配的缓冲区
            for (int j = 0; j < i; j++) {
                AudioQueueFreeBuffer(playerState.audioQueue, playerState.buffers[j]);
            }
            AudioQueueDispose(playerState.audioQueue, true);
            return -1;
        } else {
            playerState.buffers[i]->mUserData = (void *)0;
        }
    }

    // 初始化状态
    playerState.bufferIndex = 0;

    // 初始化互斥锁和条件变量
    pthread_mutex_init(&playerState.mutex, NULL);
    pthread_cond_init(&playerState.cond, NULL);

    // 开始播放
    status = AudioQueueStart(playerState.audioQueue, NULL);
    if (status != noErr) {
        elog("AudioQueueStart failed: %d\n", (int)status);
        AudioQueueDispose(playerState.audioQueue, true);
        return -2;
    }

    // 设置初始化标志
    playerState.isInitialized = 1;
    
    ilog("macOS AudioToolbox Audio player initialized\n");

    return 0;
}

static int pcmPlayer_getParams(int *channels, int *samplerate, int *bits_per_sample) {
    if (!playerState.isInitialized) {
        elog("Audio player not initialized\n");
        return -1;
    }
    
    *channels = g_channels;
    *samplerate = g_samplerate;
    *bits_per_sample = g_bits_per_sample;
    return 0;
}


static int pcmPlayer_setVolume(int db) {
    if (!playerState.isInitialized || playerState.audioQueue == NULL) {
        elog("AudioQueue is not initialized\n");
        return -1;
    }
    AudioQueueParameterValue volume0;
    AudioQueueGetParameter(playerState.audioQueue, kAudioQueueParam_Volume, &volume0); // 获取当前音量, 范围 0.0-1.0
    dlog("Current volume %f\n", volume0);
    AudioQueueParameterValue volume = volume0 * pow(10, db / 20.0);
    if (db > 0 && volume <= volume0)  volume = volume0 + 1e-6;
    if(volume < 1e-6) {
        volume = 1e-6;
    } else if(volume > 1.0) {
        volume = 1.0;
    }
    AudioQueueSetParameter(playerState.audioQueue, kAudioQueueParam_Volume, volume);
    dlog("Volume set to  %f\n", volume);

    // 返回归一化的音量值(0-100)
    return (int)(volume * 100);
}


static int pcmPlayer_write(void *pcm_data, int size) {
    if (!playerState.isInitialized || playerState.audioQueue == NULL) {
        elog("AudioQueue is not initialized\n");
        return -1;
    }
    
    if (pcm_data == NULL || size <= 0) {
        elog("Invalid PCM data or size\n");
        return -1;
    }

    int currentBufferIndex = playerState.bufferIndex;
    // 查找一个可用的 buffer
    pthread_mutex_lock(&playerState.mutex);
    while ((int)(playerState.buffers[currentBufferIndex]->mUserData) != 0) {
        dlog("Waiting for buffer %d to be available\n", currentBufferIndex);
        pthread_cond_wait(&playerState.cond, &playerState.mutex);
        dlog("Woke up\n");
    }
    pthread_mutex_unlock(&playerState.mutex);

    AudioQueueBufferRef buffer = playerState.buffers[currentBufferIndex];

    if (buffer == NULL) {
        // 没有可用的 buffer
        elog("No available buffer\n");
        return -1;
    }

    memcpy(buffer->mAudioData, pcm_data, size);
    buffer->mAudioDataByteSize = size;
    buffer->mUserData = (void *)1;

    // 将 buffer 入队
    OSStatus status = AudioQueueEnqueueBuffer(playerState.audioQueue, buffer, 0, NULL);
    if (status != noErr) {
        elog("AudioQueueEnqueueBuffer failed: %d\n", status);
        return -1;
    }

    // 更新 buffer 索引
    playerState.bufferIndex = (playerState.bufferIndex + 1) % NUM_BUFFERS;

    return 0;
}

static int pcmPlayer_deinit() {
    if (!playerState.isInitialized) {
        ilog("Audio player already deinitialized or not initialized\n");
        return 0;
    }
    
    // 等待全部播放结束
    dlog("Waiting for all buffers to be played\n");
    for(int i = 0; i < NUM_BUFFERS; i++) {
        pthread_mutex_lock(&playerState.mutex);
        while ((int)(playerState.buffers[i]->mUserData) != 0) {
            dlog("Waiting for buffer %d\n", i);
            pthread_cond_wait(&playerState.cond, &playerState.mutex);
            dlog("Woke up\n");
        }
        pthread_mutex_unlock(&playerState.mutex);
    }
    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&playerState.mutex);
    pthread_cond_destroy(&playerState.cond);
    // 停止播放
    OSStatus status = AudioQueueStop(playerState.audioQueue, false);
    if (status != noErr) {
        elog("AudioQueueStop failed: %d\n", (int)status);
        return -1;
    }
    // 释放缓冲区
    for(int i = 0; i < NUM_BUFFERS; i++) {
        status = AudioQueueFreeBuffer(playerState.audioQueue, playerState.buffers[i]);
        if (status != noErr) {
            elog("AudioQueueFreeBuffer failed: %d\n", (int)status);
        }
    }
    // 释放音频队列
    status = AudioQueueDispose(playerState.audioQueue, true);
    if (status != noErr) {
        elog("AudioQueueDispose failed: %d\n", (int)status);
        return -1;
    }
    playerState.audioQueue = NULL;

    // 标记为未初始化
    playerState.isInitialized = 0;

    dlog("macOS AudioToolbox Audio player deinitialized\n");

    return 0;
}

// 添加暂停播放功能
static int pcmPlayer_pause(int pause) {
    if (!playerState.isInitialized || playerState.audioQueue == NULL) {
        elog("AudioQueue is not initialized\n");
        return -1;
    }
    
    OSStatus status;
    if (pause) {
        status = AudioQueuePause(playerState.audioQueue);
    } else {
        status = AudioQueueStart(playerState.audioQueue, NULL);
    }
    
    if (status != noErr) {
        elog("AudioQueue %s failed: %d\n", pause ? "pause" : "resume", (int)status);
        return -1;
    }
    
    dlog("Player %s\n", pause ? "paused" : "resumed");
    return 0;
}

static pcm_player_t pcm_player = {
    .platform = MACOS,
    .name = "AudioToolbox",
    .init = pcmPlayer_init,
    .check = check_audiotoolbox_support,
    .getParams = pcmPlayer_getParams,
    .setVolume = pcmPlayer_setVolume,
    .write = pcmPlayer_write,
    .ctrl = NULL,
    .deinit = pcmPlayer_deinit,
};

__attribute__((constructor))
static void auto_register_pcm_player(void) {
    pcmPlayer_register(&pcm_player);
}